﻿~function ($, document) {
    $.namespace($.perfix + ".ui", {
        bind: function (elem, inst) {

            var uid = "$" + this.random(10000, 99999) + "" + this.random(100, 999);

            $(elem).attr("_JXUid", uid);

            this.map[uid] = inst;
        },
        fns: function (elem, fn) {
            var $self = this;
            var $this = null;
            var $uuid = null;

            if (typeof elem == "string") {
                $this = $(elem);
            } else {
                $this = elem;
            }

            $uuid = $this.attr("_JXUid");

            if ($this.length > 0 && $uuid) {
                if (fn) {
                    $this.each(function () {
                        var uid = $(this).attr("_JXUid");
                        uid && fn.call(this, $self.map[uid]);
                    });
                }
                return this.map[$uuid];
            }

            return undefined;
        },
        map: {},
        random: function (min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
    });

    $.namespace($.perfix + ".ui.unselect", {
        getStyle: (function () {
            var prefixes = ['', '-ms-', '-moz-', '-webkit-', '-khtml-', '-o-'];
            var reg_cap = /-([a-z])/g;
            function getStyle(css, el) {
                el = el || document.documentElement;
                var style = el.style, test;
                for (var i = 0, l = prefixes.length; i < l; i++) {
                    test = (prefixes[i] + css).replace(reg_cap, function ($0, $1) {
                        return $1.toUpperCase();
                    });
                    if (test in style) {
                        return test;
                    }
                }
                return null;
            }
            return getStyle;
        })(),
        userSelect: function () {
            return this.getStyle("user-select");
        },
        onUnselect: function () {
            if (typeof this.userSelect() === "string") {
                return document.documentElement.style[this.userSelect()] = "none";
            }
            document.unselectable = "on";
            document.selectstart = function () {
                return false;
            }
        },
        offUnselect: function () {
            if (typeof this.userSelect() === "string") {
                return document.documentElement.style[this.userSelect()] = "text";
            }
            document.unselectable = "off";
            document.selectstart = null;
        }
    });

    $.model($.perfix + ".ui.drag", function () {

        var drag = function (elem, opts) {

            this.config = $.extend({
                target: false,
                onStar: false,
                onStop: false,
                onMove: false
            }, opts || {});

            var _post = null;
            var $self = this;
            var $elem = this[0] = $(elem);

            $elem.on("mousedown", down).css("position", "position");

            function down(e) {
                e.stopPropagation();
                if (document.body.setCapture) {
                    document.body.setCapture();
                }
                else if (window.captureEvents) {
                    window.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP);
                }
                _post = {
                    ex: e.clientX,
                    ey: e.clientY,
                    x: $elem[0].offsetLeft,
                    y: $elem[0].offsetTop,
                    w: $elem.width(),
                    h: $elem.height()
                };

                $(document).on("mousemove", move).on("mouseup", up);

                $.ui.unselect.onUnselect();

                $self.config.onStar && $self.config.onStar.call(elem, _post.ex, _post.ey);
            };

            function move(e) {
                var y = e.clientY - _post.ey + _post.y;
                var x = e.clientX - _post.ex + _post.x;
                $self.config.onMove && $self.config.onMove.call(elem, x, y);
            };

            function up(e) {
                if (document.body.releaseCapture) {
                    document.body.releaseCapture();
                }
                else if (window.captureEvents) {
                    window.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP);
                }

                $(document).off("mousemove", move).off("mouseup", up);

                $.ui.unselect.offUnselect();

                $self.config.onStop && $self.config.onStop.call(elem);
            };
        };

        return function (elem, conf) {
            $(elem).each(function () {
                Jx.ui.bind(this, new drag(this, conf));
            });
        };
    });

    $.model($.perfix + ".ui.scrollbar", function () {

        var scrollbar = function (elem) {
            this[0] = elem;
            var $elem = $(elem);
            var $elemHeight = $elem.height();
            var contentHeight = (elem.firstElementChild || elem.firstChild).offsetHeight;
            var arrow = $elemHeight / contentHeight < 0.99;

            if (!arrow) {
                return;
            }
           
            this.inti(elem);
        };

        scrollbar.prototype = {
            inti: function (elem) {
                var self = this;
                var $elem = $(elem)
                var $elemHeight = $elem.height();
                var contentNode = null;
                if ($(elem).find("#_scrollbartag").length > 0) {
                    contentNode = $(elem).find("#_scrollbartag")[0];
                } else {
                    contentNode = elem.firstElementChild || elem.firstChild;
                }
                
                var contentHeight = contentNode.offsetHeight;
                var scrollbarHeight = Math.round($elemHeight / contentHeight * $elemHeight / 2);
                var percen = ($elemHeight - scrollbarHeight) / (contentHeight - $elemHeight)
                
                var isArrow = this.arrow = $elemHeight / contentHeight < 0.99;
                if (!isArrow) {
                    if ($(elem).find("#_scrollbartag").length > 0) {
                        $(elem.firstElementChild).css("height", $elemHeight+"px");
                        $(".scrollbardrag").hide();
                    }
                    return;
                }

                var childNode = contentNode.cloneNode(true);
                childNode.id = "_scrollbartag";

                elem.removeChild(elem.firstElementChild || elem.firstChild);
            
                var barDrag = document.createElement("div");
                $(barDrag).css({
                    "position": "absolute",
                    "top": 0,
                    "right": 0,
                    "cursor": "move",
                    "background-color": "#99b1c4",
                    "height": scrollbarHeight + "px",
                    "width": 7 + "px",
                    "-ms-filter":"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)",
                    "filter":"alpha(opacity=30)",
                    "opacity": 0.3
                }).attr("class", "scrollbardrag");

                var barPanl = document.createElement("div");
                $(barPanl).css({
                    "height": $elemHeight + "px",
                    "overflow": "hidden"
                });

                var border = $(barDrag).css("border-top-width").replace("px", "");
                scrollbarHeight += (border == "medium" ? 0 : +border);

                barPanl.appendChild(barDrag)
                barPanl.appendChild(childNode);

                elem.appendChild(barPanl);

                $.ui.drag(barDrag, {
                    onMove: _onDrag
                });

                $(barPanl).on("mousewheel", _onMousewheel);

                $(barPanl).hover(function () {
                    barDrag.style.display = self.arrow ? "block" : "none";
                }, function () {
                    barDrag.style.display = "none"
                });

                function _onDrag(x, y) {
                    if (!self.arrow) { return; }
                   
                    if (y <= 0) {
                        barPanl.scrollTop = 0;
                        $(this).css("top", "0px");
                    } else if (y + scrollbarHeight >= $elemHeight) {
                        barPanl.scrollTop = contentHeight;
                        $(this).css("top", ($elemHeight - scrollbarHeight) + "px");
                    } else {
                        $(this).css("top", y + "px");
                        barPanl.scrollTop = Math.round(y / percen);
                    }
                };

                function _onMousewheel(event, delta, deltaX, deltaY) {

                    if (!self.arrow) { return; }

                    var top = Number($(barDrag).css("top").replace("px", "") || 0);

                    if (delta < 0) {
                        top += 20;
                    } else {
                        top -= 20;
                    }

                    if (top <= 0) {
                        $(barDrag).css("top", 0 + "px");
                        barPanl.scrollTop = 0;
                    } else if (top + scrollbarHeight >= $elemHeight) {
                        $(barDrag).css("top", ($elemHeight - scrollbarHeight) + "px");
                        barPanl.scrollTop = contentHeight;
                    } else {
                        $(barDrag).css("top", top + "px");
                        barPanl.scrollTop = Math.round(top / percen);
                    }
                };
            },
            resize: function () {
                this.inti(this[0]);
            }
        };

        return function (elem, conf) {
            $(elem).each(function () {
                Jx.ui.bind(this, new scrollbar(this, conf));
            });
        };
    });
}(Jx, document);